//3.1.2-1
/**
 * @param {string} str1
 * @remark 加法运算符
 * @remark 两个字符串相加，这时加法运算符会变成连接运算符，返回一个新的字符串，将两个原字符串连接在一起。
 * @remark 加法运算符是在运行时决定，到底是执行相加，还是执行连接。也就是说，运算子的不同，导致了不同的语法行为，这种现象称为“重载”
 */
function frist(str1) {
    var a=true + true;
    var b='a'+'bc';
    var c='3' + 4 + 5 ;
    var d=3 + 4 + '5' ;
    return {
        return1:a,
        return2:b,
        return3:c,
        return4:d
    }
}
/**
 * @param {string} str2
 * @remark 除了加法运算符，其他算术运算符（比如减法、除法和乘法）都不会发生重载。它们的规则是：所有运算子一律转为数值，再进行相应的数学运算。
 */
function frist2(str2) {
    var a=true - true;
    var b='a'-'bc';
    var c='3'-4-5 ;
    var d=3-4-'5' ;
    return {
        return1:a,
        return2:b,
        return3:c,
        return4:d
    }
}
// console.log(frist())//{return1: 2, return2: "abc", return3: "345", return4: "75"}
// console.log(frist2())//{return1: o, return2: NaN, return3: -6, return4: -6}

// 3.1.2-2
/**
 * @param {string} str3
 * @remark 如果运算子是对象，必须先转成原始类型的值，然后再相加。
 * @remark 对象obj转成原始类型的值是[object Object]，再加2就得到了上面的结果。
 */
function frist3(str3) {
    var obj = { p: 1 };
    return obj + 2 
}

/**
 * @param {string} str4
 * @remark 定义valueOf方法或toString方法，得到想要的结果。
 * @remark 2是数值，使用加法远算符时是数字相加；'2'是字符串，使用加法运算符时非字符串被自动转为字符串，然后进行连接。
 */
function frist4(str4) {
    var obj = { p: 1 };
    obj.valueOf= function(){return 2};
    return obj + 3 
}
function frist5(str4) {
    var obj = { p: 1 };
    obj.toString= function(){return '2'};
    return obj + 3 
}

/**
 * @param {string} str5
 * @remark 运算子是一个Date对象的实例，那么会优先执行toString方法。
 */
function frist6(str5) {
    var obj = new Date();
    obj.toString= function(){return '2018-09-07'};
    obj.valueOf= function(){return 2};
    return obj + 3 
}
// console.log(frist3())//'[object Object]2'
// console.log(frist4())//5
// console.log(frist5())//'23'
// console.log(frist6())//'2018-09-073'

// 3.1.3
/**
 * @param {string} str6
 * @remark 余数运算符
 * @remark 运算结果的正负号由第一个运算子的正负号决定。
 */
function frist7(str6) {
    a=11 % -5;
    b=-1 % 2
    return {
        return1:a,
        return2:b
    }
}

/**
 * @param {string} str7
 * @remark 为了得到负数的正确余数值，可以先使用绝对值函数Math.abs。
 */
function frist8(str7) {
    function isOdd(n) {
        return Math.abs(n % 2) === 1;
      }
    return {
        return1:isOdd(-5) ,
        return2:isOdd(-4) 
    }
}

/**
 * @param  {string} str8
 * @remark 余数运算符还可以用于浮点数的运算。但是，由于浮点数不是精确的值，无法得到完全准确的结果。
 */
function frist9(str8) {
    var a=6.5 % 2.1;
    var b=6.5 % -2.0;
    // return a
    return b//0.5
}
// console.log(frist7())//{return1: 1, return2: -1}
// console.log(frist8())//{return1: true, return2: false}
// console.log(frist9())//0.19999999999999973

// 3.1.4
/**
 * @param {string} str9
 * @remark 自增和自减运算符,运算之后，变量的值发生变化
 * @remark 就是放在变量之后，会先返回变量操作前的值，再进行自增/自减操作；放在变量之前，会先进行自增/自减操作，再返回变量操作后的值。
 */
function frist10(str9) {
    var a=1;
    a++;//a=2
    return {
        return1:a,//a=2
        return2:++a//a=3,先自增再返回
    }
}
// console.log(frist10())//{return1: 2, return2: 3}

// 3.1.5
/**
 * @param {string} str10
 * @remark 数值运算符（+）同样使用加号，但它是一元运算符（只需要一个操作数），而加法运算符是二元运算符（需要两个操作数）。
 * @remark 数值运算符的作用在于可以将任何值转为数值（与Number函数的作用相同）。
 */
function frist11(str10) {
    var a=+true;
    var b=+false;
    var c=+[];
    var d=+{};
    return {
        return1:a,
        return2:b,
        return3:c,
        return4:d
    }
}

/**
 * @param {string} str11
 * @remark 负数值运算符（-），也同样具有将一个值转为数值的功能，只不过得到的值正负相反。连用两个负数值运算符，等同于数值运算符
 */
function frist12(str11) {
    var a=-true;
    var b=-false;
    return {
        return1:a,
        return2:b
    }
}

// console.log(frist11())//{return1: 1, return2: 0, return3: 0, return4:NaN}
// console.log(frist12())//{return1: -1, return2: 0}

// 3.1.6
/**
 * @param {string} str12
 * @remark 指数运算符
 */
function frist13(str12) {
    return 2 ** 4 
}

/**
 * @param {string} str13
 * @remark 指数运算符是右结合，而不是左结合。即多个指数运算符连用时，先进行最右边的计算
 */
function frist14(str13) {
    return 2 ** 3 ** 2 //相当于 2 ** (3 ** 2)
}
// console.log(frist13())//16
// console.log(frist14())//256

// 3.1.7
/**
 * @param {string} str14
 * @remark 赋值运算符（Assignment Operators）用于给变量赋值。最常见的赋值运算符，当然就是等号（=）。
 */
function frist15(str14) {
    var a=1;
    return a
}

/**
 * @param {string} str15
 * @remark 赋值运算符还可以与其他运算符结合，形成变体。下面是与算术运算符的结合。
 */
function frist16(str15) {
    var a=1;
    a+=2;//a=a+2
    return a
}
// console.log(frist15())//1
// console.log(frist16())//3

//3.2.2
/**
 * @param {string} str16
 * @remark 非相等运算符：字符串的比较 
 * @remark JavaScript 引擎内部首先比较首字符的 Unicode 码点。如果相等，再比较第二个字符的 Unicode 码点，以此类推。
 * @remark 由于所有字符都有 Unicode 码点，因此汉字也可以比较。
 */
function frist17(str16) {
    return {
        return1:'cat' > 'Cat',
        return2:'大' > '小' 
    }
}
// console.log(frist17())//{ return1: true, return2: false }

// 3.2.3
/**
 * @param {string} str17
 * @remark 非相等运算符：非字符串的比较 
 * @remark 如果两个运算子都是原始类型的值，则是先转成数值再比较。
 */
function frist18(str17) {
    return {
        return1:true > false,//true=1,false=0
        return2:'3' > 4 //3=3,4=4
    }
}

/**
 * @param {string} str18
 * @remark 任何值（包括NaN本身）与NaN使用非相等运算符进行比较，返回的都是false。
 */
function frist19(str18) {
    return {
        return1:NaN > NaN,
        return2:NaN < NaN 
    }
}

/**
 * @param {string} str19
 * @remark 如果运算子是对象，会转为原始类型的值，再进行比较。
 * @remark 对象转换成原始类型的值，算法是先调用valueOf方法；如果返回的还是对象，再接着调用toString方法
 * @remark JavaScript 首先将数组 x 转换成字符串，然后比较这两个字符串。字符串比较是逐字符比较的，从左到右比较字符的 Unicode 值。在这里，首先比较的是 '2' 的第一个字符 '2' 和 '11' 的第一个字符 '1'。由于 '2' 的 Unicode 值大于 '1'，所以 '2' 被认为比 '11' 大。
 */
function frist20(str19) {
    var x = [2];
    return x > '11'
    // 等同于 [2].valueOf().toString() > '11'
    // 即 '2' > '11'
}

/**
 * @param {string} str18
 * @remark 两个对象之间的比较也是如此。
 */
function frist21(str18) {
    return ({ x: 2 }) >= ({ x: 1 }) 
    // 等同于 ({ x: 2 }).valueOf().toString() >= ({ x: 1 }).valueOf().toString()
    // 即 '[object Object]' >= '[object Object]'
}
// console.log(frist18())//{ return1: true, return2: false }
// console.log(frist19())//{ return1: false, return2: false }
// console.log(frist20())//true
// console.log(frist21())//true

// 3.2.4
/**
 * @param {string} str20
 * @remark 严格相等运算符
 * @remark 如果两个值的类型不同，直接返回false。
 * @remark 数值的1与字符串的“1”、布尔值的true与字符串"true"，因为类型不同，结果都是false。
 */
function frist22(str20) {
    return{ 
        return1:1 === '1',
        return2:true === 'true' 
    }
}

/**
 * @param {string} str21
 * @remark 同一类型的原始类型的值（数值、字符串、布尔值）比较时，值相同就返回true，值不同就返回false。
 * @remark NaN与任何值都不相等（包括自身）。
 */
function frist23(str21) {
    return{ 
        return1:1 === 0x1,
        return2:NaN === NaN ,
        return3:+0 === -0 
    }
}

/**
 * @param {string} str22
 * @remark 两个复合类型（对象、数组、函数）的数据比较时，不是比较它们的值是否相等，而是比较它们是否指向同一个地址。
 * @remark 对于复合类型的值，严格相等运算比较的是，它们是否引用同一个内存地址，而运算符两边的空对象、空数组、空函数的值，都存放在不同的内存地址，结果当然是false。
 */
function frist24(str22) {
    return{ 
        // return1:{} === {} ,
        // return2:[] === [],
        // return3:function () {} === function () {} 
    }
}

/**
 * @param {string} str23
 * @remark 如果两个变量引用同一个对象，则它们相等。
 */
function frist25(str23) {
    var v1 = {};
    var v2 = v1;
    return v1 === v2 
}

/**
 * @param {string} str24
 * @remark 对于两个对象的比较，严格相等运算符比较的是地址，而大于或小于运算符比较的是值。
 */
function frist26(str24) {
    var obj1 = {};
    var obj2 = {};
    return{ 
        return1:obj1 > obj2,
        return2:obj1 < obj2,
        return3:obj1 == obj2 
    }
}

/**
 * @param {string} str25
 * @return undefined和null与自身严格相等。
 */
function frist27(str25) {
    return{ 
        return1:null === null,
        return2:undefined === undefined 
    }
}

/**
 * @param {string} str26
 * @remark 由于变量声明后默认值是undefined，因此两个只声明未赋值的变量是相等的。
 */
function frist28(str26) {
    var v1;
    var v2;
    return v1 === v2
}
// console.log(frist22())//{ return1: false, return2: false }
// console.log(frist23())//{ return1: true, return2: false, return3: true }
// console.log(frist24())
// console.log(frist25())//true
// console.log(frist26())//{ return1: false, return2: false, return3: false }
// console.log(frist27())//{ return1: true, return2: true }
// console.log(frist28())//true

// 3.2.5
/**
 * @param {string} str27
 * @remark “严格不相等运算符”（!==），它的算法就是先求严格相等运算符的结果，然后返回相反值。
 */
function frist29(str27) {
    return 1 !== '1' 
}
// console.log(frist29())//true

// 3.2.6
/**
 * @param {string} str28
 * @remark 相等运算符用来比较相同类型的数据时，与严格相等运算符完全一样。
 */
function frist30(str28) {
    return 1 == 1.0
}

/**
 * @param {string} str29
 * @remark 相等运算符---原始类型的值会转换成数值再进行比较
 * @remark Number('true')=NaN, Number(true)=1
 */
function frist31(str29) {
    return {
        return1: 1 == true,
        return2: 0 == false,
        return3: 'true' == true,//等同于 Number('true') === Number(true),等同于 NaN === 1
        return4: '' == 0
    }
}

/**
 * @param {string} str30
 * @remark 对象（这里指广义的对象，包括数组和函数）与原始类型的值比较时，对象转换成原始类型的值，再进行比较。
 * @remark []可以转化为字符串或数字。
 */
function frist32(str30) {
    return{ 
        return1:[1] == 1,
        return2:[1] == '1',
        return3:[1, 2] == '1,2',
        return4:[2] == true,

    }
}

/**
 * @param {string} str31
 */
function frist33(str31) {
    const obj = {
        valueOf: function () {
          console.log('执行 valueOf()');
          return obj;
        },
        toString: function () {
          console.log('执行 toString()');
          return 'foo';
        }
    };  
    return obj == 'foo'
}

/**
 * @param {string} str32
 * @remark undefined和null只有与自身比较，或者互相比较时，才会返回true；与其他类型的值比较时，结果都为false。
 */
function frist34(str32) {
    return{ 
        return1: undefined == null,
        return2: undefined === null,
        return3: undefined == undefined,
        return4: undefined === undefined,
        return5: null == undefined,
        return6: null === undefined,
        return7: null == null,
        return8: null === null,
        return9: 0 == null,
        return10: 0 == undefined
    }
}

/**
 * @param {string} str33
 * @remark 相等运算符隐藏的类型转换，会带来一些违反直觉的结果。
 */
function frist35(str33) {
    return{ 
        return1: 0 == '',
        return2: 0 == '0',
        return3: 2 == true,
        return4: 2 == false,
        return5: false == 'false',
        return6: false == '0',
        return7: false == undefined,
        return8: false == null,
        return9: null == undefined,
        return10: ' \t\r\n ' == 0
    }
}
// console.log(frist30())//true
// console.log(frist31())//{ return1: true, return2: true, return3: false, return4: true}
// console.log(frist32())//{ return1: true, return2: true, return3: true, return4: false }
// console.log(frist33())//true
// console.log(frist34())
/*
  return1: true,
  return2: false,
  return3: true,
  return4: true,
  return5: true,
  return6: false,
  return7: true,
  return8: true,
  return9: false,
  return10: false
*/
// console.log(frist35())
/*
  return1: true,
  return2: true,
  return3: false,
  return4: false,
  return5: false,
  return6: true,
  return7: false,
  return8: false,
  return9: true,
  return10: true
*/

//3.2.7
/**
 * @param {string} str34
 * @remark 相等运算符有一个对应的“不相等运算符”（!=），它的算法就是先求相等运算符的结果，然后返回相反值。
 */
function frist36(str34) {
    return 1 != '1'
}
// console.log(frist36())//false

//3.3.2
/**
 * @param {string} str35
 * @remark 取反运算符是一个感叹号，用于将布尔值变为相反值，即true变成false，false变成true。
 */
function frist37(str35) {
    return {
        return1:!true,
        return2:!false
    }
}

/**
 * @param {string} str36
 * @remark 对于非布尔值，取反运算符会将其转为布尔值。可以这样记忆，以下六个值取反后为true，其他值都为false。
 */
function frist38(str36) {
    return{ 
        return1: !undefined,
        return2: !null,
        return3: !0,
        return4: !+0,
        return5: !NaN ,
        return6: !'',
        return: !'foo'
    }
}

/**
 * @param {string} str37
 * @remark 如果对一个值连续做两次取反运算，等于将其转为对应的布尔值，与Boolean函数的作用相同。这是一种常用的类型转换的写法。
 * @remark 对于任何非零和非空值，包括对象，数组，字符串，数字等等，JavaScript会将其视为true。只有两个值被视为false，那就是0和空字符串("")。
 */
function frist39(str37) {
    var x = 1;
    return !!x
}
// console.log(frist37())//{ return1: false, return2: true }
// console.log(frist38())//{ return1: true, return2: true, return3: false, return4: false
/*
{
  return1: true,
  return2: true,
  return3: true,
  return4: true,
  return5: true,
  return6: true,
  return: false
}
*/
// console.log(frist39())//true

//3.3.3
/**
 * @param {string} str38
 * @remark 且运算符（&&）往往用于多个表达式的求值。
 */
function frist40(str38) {
    return {
        return1: true && false,
        return2: true && 1,
        return3: false && '',
        return4: false && 0,
        return5: '' && null,
        return6: 0 && 'foo'
    }
}

/**
 * @param {string} str39
 * @remark 这种跳过第二个运算子的机制，被称为“短路”
 */
function frist41(str39) {
    var i = false;
    if (i) {
        doSomething();
    }  
    return i && doSomething();    
}

/**
 * @param {string} str40
 * @remark 且运算符可以多个连用，这时返回第一个布尔值为false的表达式的值。如果所有表达式的布尔值都为true，则返回最后一个表达式的值。
 */
function frist42(str40) {
    var x = 1;
    return{
        return1:true && false && '' && null && undefined && x && 'foo',
        return2:1 && 2 && 3
    }
}
// console.log(frist40())//{ return1: false, return2: 1, return3: false, return4:false, return5: '', return6: 0 }
// console.log(frist41())//false
// console.log(frist42())//{ return1: false, return2: 3 }

//3.3.4
/**
 * @param {string} str41
 * @remark 逻辑或运算符（||）与且运算符类似，也是用于多个表达式的求值。
 */
function frist43(str41) {
    return{
        return1:'t' || '' ,
        return2: 0 || 'foo'
    }
}

/**
 * @param {string} str42
 * @remark 或运算符可以多个连用，这时返回第一个布尔值为true的表达式的值。如果所有表达式都为false，则返回最后一个表达式的值。
 */
function frist44(str42) {
    var x = 1;
    return{
        return1:false || 0 || '',
        return2:0 || 1 || 2
    }
}

/**
 * @param {string} str43
 * @remark 或运算符常用于为一个变量设置默认值
 * @remark 如果函数调用时，没有提供参数，则该参数默认设置为空字符串。
 */
function frist45(str43) {
    function saveText(text) {
        text = text || '';
        return text
    }
    return saveText()
}
// console.log(frist43())//{ return1: 't', return2: 'foo' }
// console.log(frist44())//{ return1: '' , return2: 1 }
// console.log(frist45())//空字符串

//3.3.5
/**
 * @param {string} str44
 * @remark 三元条件运算符由问号（?）和冒号（:）组成，分隔三个表达式
 * @remark 如果第一个表达式的布尔值为true，则返回第二个表达式的值，否则返回第三个表达式的值。
 */
function frist46(str44) {
    return{
        return:'t' ? 'hello' : 'world',
        return2:0 ? 'hello' : 'world'
    }
}

/**
 * @param {string} str45
 * @remark 三元条件表达式与if...else语句具有同样表达效果
 */
function frist47(str45) {
    return true ? 'T' : 'F'
}
// console.log(frist46())//{ return: 'hello', return2: 'world' }
// console.log(frist47())//T

//3.4.2
/**
 * @param {string} str46
 * @remark 二进制或运算符（|）逐位比较两个运算子，两个二进制位之中只要有一个为1，就返回1，否则返回0。
 * @remark 0和3的二进制形式分别是00和11，所以进行二进制或运算会得到11（即3）
 */
function frist48(str46) {
    return 0 | 3
}

/**
 * @param {string} str47
 * @remark 位运算只对整数有效，遇到小数时，会将小数部分舍去，只保留整数部分。
 */
function frist49(str47) {
    return {
        return1:0.1 | 0.2,
        return2:2.9 | 0 
    }
}

/**
 * @param {string} str48
 * @remark 这种取整方法不适用超过32位整数最大值2147483647的数。
 */
function frist50(str48) {
    return 2147483649.4 | 0
}
// console.log(frist48())//3
// console.log(frist49())//{ return1: 0, return2: 2 }
// console.log(frist50())//-2147483647

//3.4.3
/**
 * @param {string} str49
 * @remark 二进制与运算符（&）的规则是逐位比较两个运算子，两个二进制位之中只要有一个位为0，就返回0，否则返回1。
 */
function frist51(str49) {
    return 0 & 3 
}
// console.log(frist51())//0

//3.4.4
/**
 * @param {string} str50
 * @reamrk 二进制否运算符（~）将每个二进制位都变为相反值（0变为1，1变为0）。
 */
function frist52(str50) {
    return ~0
}

/**
 * @param {string} str51
 * @remark 二进制否运算遇到小数时，也会将小数部分舍去，只保留整数部分。所以，对一个小数连续进行两次二进制否运算，能达到取整效果。
 */
function frist53(str51) {
    return ~~0.4
}

/**
 * @param {string} str52
 * @remark 对字符串进行二进制否运算，JavaScript 引擎会先调用Number函数，将字符串转为数值。
 */
function frist54(str52) {
    return ~'10'
}

/**
 * @param {string} str53
 * @remark 对于其他类型的值，二进制否运算也是先用Number转为数值，然后再进行处理。
 */
function frist55(str53) {
    return ~[]
}

// console.log(frist52())//-1
// console.log(frist53())//0
// console.log(frist54())//-11
// console.log(frist55())//-1

//3.4.5
/**
 * @param {string} str54
 * @remark 异或运算（^）在两个二进制位不同时返回1，相同时返回0
 */
function frist56(str54) {
    return 1 ^ 3
}

/**
 * @param {string} str55
 * @remark 连续对两个数a和b进行三次异或运算，a^=b; b^=a; a^=b;，可以互换它们的值。这意味着，使用“异或运算”可以在不引入临时变量的前提下，互换两个变量的值。
 */
function frist57(str55) {
    var a = 10, b = 99;
    a ^= b;
    b ^= a;
    a ^= b;
    return [a, b]
}

/**
 * @param {string} str56
 * @remark 异或运算也可以用来取整。
 */
function frist58(str56) {
    return 2147.1 ^ 0
}
// console.log(frist56())//2
// console.log(frist57())//[ 99, 10 ]
// console.log(frist58())//2147

//3.4.6
/**
 * @param {string} str57
 * @remark 左移运算符（<<）将运算子向二进制表示形式的最左边添加若干0，然后返回最终结果。
 * @remark 4 的二进制形式为100，左移一位为1000（即十进制的8）,相当于乘以2的1次方
 */
function frist59(str57) {
    return 4 << 1
}

/**
 * @param {string} str58
 * @rearm 如果左移0位，就相当于将该数值转为32位整数，等同于取整，对于正数和负数都有效。
 */
function frist60(str58) {
    return 4.5 << 0
}

/**
 * @param {string} str59
 * @remark 左移运算符用于二进制数值非常方便。
 */
function frist61(str59) {
    var color = {r: 186, g: 218, b: 85};

    var rgb2hex = function(r, g, b) {
      return '#' + ((1 << 24) + (r << 16) + (g << 8) + b)
        .toString(16) // 先转成十六进制，然后返回字符串
        .substr(1);   // 去除字符串的最高位，返回后面六个字符串
    }
    
    return rgb2hex(color.r, color.g, color.b)
}
// console.log(frist59())//8
// console.log(frist60())//4
// console.log(frist61())//#bada55

//3.4.7
/**
 * @param {string} str60
 * @remark 右移运算符（>>）表示将一个数的二进制值向右移动指定的位数。如果是正数，头部全部补0；如果是负数，头部全部补1。
 */
function frist62(str60) {
    return 4 >> 1
}

/**
 * @param {string} str61
 * @remark 右移运算可以模拟 2 的整除运算。
 */
function frist63(str61) {
    return 5 >> 1
}

// console.log(frist62())//2
// console.log(frist63())//2

//3.4.8
/**
 * @param {string} str62
 * @remark 头部补零的右移运算符（>>>）与右移运算符（>>）只有一个差别，就是一个数的二进制形式向右移动时，头部一律补零，而不考虑符号位。所以，该运算总是得到正值。对于正数，该运算的结果与右移运算符（>>）完全一致，区别主要在于负数。
 */
function frist64(str62) {
    return {
        return1:4 >>> 1,
        return2:-4 >>> 1
    }
}

/**
 * @param {string} str63
 * @remark 查看一个负整数在计算机内部的储存形式，最快的方法就是使用这个运算符。
 */
function frist65(str63) {
    return -1 >>> 0
}
// console.log(frist64())//{ return1: 2, return2: 2147483646}
// console.log(frist65())//4294967295

//3.4.9
/**
 * @param {string} str64
 * @remark 位运算符可以用作设置对象属性的开关,可以用二进制与运算，检查当前设置是否打开了指定开关
 */
function frist66(str64) {
    // 定义一些开关常量
    const SWITCH_1 = 0b0001; // 代表开关1
    const SWITCH_2 = 0b0010; // 代表开关2
    const SWITCH_3 = 0b0100; // 代表开关3
    const SWITCH_4 = 0b1000; // 代表开关4

    // 定义一个对象，用来存储开关状态
    let switchStatus = 0b0000; // 初始状态，所有开关都关闭

    // 打开开关2和开关4
    switchStatus = switchStatus | SWITCH_2 | SWITCH_4;

    // 检查开关1是否打开
    if ((switchStatus & SWITCH_1) === SWITCH_1) {
        console.log('开关1已打开');
    } else {
        console.log('开关1已关闭');
    }

    // 检查开关2是否打开
    if ((switchStatus & SWITCH_2) === SWITCH_2) {
        console.log('开关2已打开');
    } else {
        console.log('开关2已关闭');
    }

    // 关闭开关4
    switchStatus = switchStatus & ~SWITCH_4;

    // 检查开关4是否打开
    if ((switchStatus & SWITCH_4) === SWITCH_4) {
        console.log('开关4已打开');
    } else {
        console.log('开关4已关闭');
    }
}
// console.log(frist66())
/*
开关1已关闭
开关2已打开
开关4已关闭
*/

//3.5.1
/**
 * @param  {string} str65
 * @remark void运算符的作用是执行一个表达式，然后不返回任何值，或者说返回undefined。
 * @remark 两种写法。
 */
function frist67(str65) {
    return {
        return1:void 0 ,
        return2:void (0)
    }
}

/**
 * @param {string} str65 
 * @returns return2的x被覆盖了。
 */
function frist68(str65) {
    var x = 3;
    return {
        return1:void (x = 5),
        return2:x
    }
}


// console.log(frist67())//{ return1: undefined, return2: undefined}
// console.log(frist68())//{ return1: undefined, return2: 3}

//3.5.2
/**
 * @param {string} str69
 * @remark 逗号运算符用于对两个表达式求值，并返回后一个表达式的值。
 */
function frist69(str69) {
    var x = 0;
    var y = (x++, 10);
    return{
        return1:x,
        return2:y
    }
}

/**
 * @param {string} str69
 * @remark 逗号运算符的一个用途是，在返回一个值之前，进行一些辅助操作。
 */
function frist70(str69) {
    var value = (console.log('Hi!'), true);
    return value;
}

// console.log(frist69())//{ return1: 1, return2: 10}
// console.log(frist70())//Hi! true

//3.5.3-1
/**
 * @param {string} str71
 * @remark 优先级高的运算符先执行，优先级低的运算符后执行。
 */
function frist71(str71) {
    return 4 + 5 * 6 //4 + (5 * 6) 
}

/**
 * @param {string} str71
 * @remark 多个运算符混写
 * @remark var y = ((arr.length <= 0) || (arr[0] === undefined)) ? x : arr[0];
 */
function frist72(str71) {
    var x = 1;
    var arr = [];
    var y = arr.length <= 0 || arr[0] === undefined ? x : arr[0];
    return y;
}

// console.log(frist71())//34
// console.log(frist72())//1

//3.5.3-2
/**
 * @param {string} str73
 * @remark 圆括号（()）可以用来提高运算的优先级，因为它的优先级是最高的，即圆括号中的表达式会第一个运算。
 */
function frist73(str73) {
    return (4 + 5) * 6 
}

/**
 * @param {string} str73
 * @remark 因为圆括号不是运算符，所以不具有求值作用，只改变运算的优先级。
 */
function frist74(str73) {
    var x = 1;
    (x) = 2;
    return x
}

/**
 * @param {string} str73
 * @remark 函数放在圆括号中，会返回函数本身。如果圆括号紧跟在函数的后面，就表示调用函数。
 */
function frist75(str73){
    function f() {
        return 1;
      }
    return {
        return1:f(),
        return2:f
    }   
}

/**
 * @param {string} str73
 * @remark 圆括号之中，只能放置表达式，如果将语句放在圆括号之中，就会报错。
 */
// function frist76(str73){
//     (var x = 1);
//     x = 2;
//     return x
// }
// console.log(frist73())//54
// console.log(frist74())//2
// console.log(frist75())//{ return1: 1, return2: [Function: f]  }
// console.log(frist76())// SyntaxError: Unexpected token var

//3.5.3-3
/**
 * @param {string} str77
 * @remark JavaScript 语言的大多数运算符是“左结合”
 * @remark 少数运算符是“右结合”，其中最主要的是赋值运算符（=）和三元条件运算符（?:）。
 */
function frist77(str77) {
    return {
        return1:w = x = y = z,
        //w = (x = (y = z))
        return2:q = a ? b : c ? d : e ? f : g
        //q = a ? b : (c ? d : (e ? f : g))
    }
}

/**
 * @param {string} str77
 * @remark 指数运算符（**）也是右结合。
 */
function frist78(str77) {
    return 2 ** 3 ** 2 
}
// console.log(frist77())
// console.log(frist78())//512
